package com.nice.demo.test;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathEffect;
import android.graphics.PathMeasure;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Xfermode;
import android.nfc.Tag;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.view.animation.AccelerateInterpolator;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.Toast;

import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.nice.demo.MyHandCache;
import com.nice.demo.test.bean.PathInfo;
import com.nice.demo.test.bean.PointInfo;


import org.json.JSONException;
import org.json.JSONObject;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.LongFunction;

/**
 * author : jc
 * date   : 2020/3/13
 * desc   :
 * version: 1.0
 */
public class MyHandWritingCoreView extends View {
    private static String TAG = "MyHandWritingCoreView";
    private static final float MAX_PEN_SIZE = 2.5F;
    private static final int MIN_PEN_SIZE = 1;
    private static final int PAINT_SIZE = 2;
    public static final int AXIS_ARROW_HEIGHT = 10;
    public static final int AXIS_OTHER_LENGTH = 4;
    IHandWritingViewCache handWritingViewCache;
    private ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener;
    MotionEventCallback motionEventCallback;
    MyHandWritingView.RecycleListener recycleListener;
    HandWritingCanvas handWritingCanvas;
    Path tilePath;
    PathMeasure pathMeasure;
    Canvas writingViewCanvas;
    Bitmap writingViewBitmap;
    private Path mPath;
    private Paint mPaint;
    int mSetPenColor;
    Paint paintDither;
    private Paint mBitmapPaint;
    private int endX;
    private int endY;
    private int oldX;
    private int oldY;
    private int minX;
    private int minY;
    private int maxX;
    private int maxY;
    private List<PathInfo> pathsList;
    private View actionDownView;
    private int mWidth;
    private int mHeight;
    private int mStrokeWidth;
    private int mStrokeHeight;
    private DrawType mDrawType;
    private boolean mIsRubber;
    private boolean canDraw;
    private int validAbs;
    private boolean hasRange;
    private String[] ranges;
    private int eraserSize;
    private int eraserHalf;
    private Bitmap rubber;
    float lastPressure;
    float lastLength;
    Path linePath;
    private boolean isNeedRedraw;
    private int rectMinX;
    private int rectMinY;
    private int rectMaxX;
    private int rectMaxY;
    private boolean mIsStrokesChanged;
    private boolean mIsDispatch;
    private boolean mIsTempChangeRubber;
    private Paint mGeometryPaint;
    private Path mGeometryPath;
    private PathInfo mGeometryTempInfo;
    private boolean mIsGeometryEditable;
    private IGeometryListener mGeometryListener;
    private int mAxisUnit;
    private AtomicInteger mAtomicInteger;

    //绘画路线保存集合
    private SparseArray<PathInfo> strokeList;
    private int indexStroke = 0;
    private List<PointInfo> strokePointInfoList = new ArrayList<>();
    private PathInfo strokePathInfo = null;


    public MyHandWritingCoreView(Context context) {
        this(context, (AttributeSet) null);
    }

    public MyHandWritingCoreView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MyHandWritingCoreView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.tilePath = new Path();
        this.pathMeasure = new PathMeasure();
        this.paintDither = new Paint(4);
        this.oldX = -1;
        this.oldY = -1;
        this.minX = 0;
        this.minY = 0;
        this.maxX = 0;
        this.maxY = 0;
        this.pathsList = new ArrayList();
        this.mDrawType = DrawType.CURVE;
        this.validAbs = 2;
        this.ranges = new String[5];
        this.eraserSize = 20;
        this.eraserHalf = this.eraserSize / 2;
        this.rubber = Bitmap.createBitmap(this.eraserSize, this.eraserSize, Bitmap.Config.ARGB_8888);
        this.lastPressure = 0.0F;
        this.lastLength = 0.0F;
        this.linePath = new Path();
        this.isNeedRedraw = true;
        this.rectMinX = 0;
        this.rectMinY = 0;
        this.rectMaxX = 0;
        this.rectMaxY = 0;
        this.mAxisUnit = 50;
        this.mAtomicInteger = new AtomicInteger();
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "constructor >>> context = [" + context + "], attrs = [" + attrs + "], defStyleAttr = [" + defStyleAttr + "]", new Object[0]);
        }

        this.initArgc();
        this.initCoreWriting();
        this.initHandViewObserver();
    }

    public MyHandWritingCoreView(Context context, int width, int height) {
        super(context);
        this.tilePath = new Path();
        this.pathMeasure = new PathMeasure();
        this.paintDither = new Paint(4);
        this.oldX = -1;
        this.oldY = -1;
        this.minX = 0;
        this.minY = 0;
        this.maxX = 0;
        this.maxY = 0;
        this.pathsList = new ArrayList();
        this.mDrawType = DrawType.CURVE;
        this.validAbs = 2;
        this.ranges = new String[5];
        this.eraserSize = 20;
        this.eraserHalf = this.eraserSize / 2;
        this.rubber = Bitmap.createBitmap(this.eraserSize, this.eraserSize, Bitmap.Config.ARGB_8888);
        this.lastPressure = 0.0F;
        this.lastLength = 0.0F;
        this.linePath = new Path();
        this.isNeedRedraw = true;
        this.rectMinX = 0;
        this.rectMinY = 0;
        this.rectMaxX = 0;
        this.rectMaxY = 0;
        this.mAxisUnit = 50;
        this.mAtomicInteger = new AtomicInteger();
        this.mWidth = width == 0 ? 1 : width;
        this.mHeight = height == 0 ? 1 : height;
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "constructor >>> context = [" + context + "], width = [" + width + "], height = [" + height + "]", new Object[0]);
        }

        ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(this.mWidth, this.mHeight);
        super.setLayoutParams(layoutParams);
        this.initArgc();
        this.initCoreWriting();
        this.initBitmapCanvasBitmapPaint();
    }

    private void initArgc() {
        this.strokeList = new SparseArray<>();
        this.canDraw = true;
        this.mDrawType = DrawType.CURVE;
        this.mIsStrokesChanged = false;
    }

    private void initCoreWriting() {
        this.mPath = new Path();
        this.mPath.reset();
        this.mPaint = new Paint(4);
        this.mPaint.setColor(-16776961);
        this.mPaint.setStyle(Paint.Style.STROKE);
        this.mPaint.setStrokeWidth(2.0F);
        this.mPaint.setStrokeJoin(Paint.Join.ROUND);
        this.mPaint.setStrokeCap(Paint.Cap.ROUND);
        this.mGeometryPaint = new Paint(1);
        this.mGeometryPaint.setColor(-16777216);
        this.mGeometryPaint.setStrokeWidth(2.0F);
        this.mGeometryPaint.setStyle(Paint.Style.STROKE);
        this.mGeometryPath = new Path();
    }

    private void initBitmapCanvasBitmapPaint() {
        if (this.mWidth > 0 && this.mHeight > 0) {
            if (this.handWritingCanvas == null || this.handWritingCanvas.width != this.mWidth || this.handWritingCanvas.height != this.mHeight) {
                this.mBitmapPaint = new Paint(2);
                Paint circlePaint = new Paint(4);
                circlePaint.setColor(Color.parseColor("#59d1a3"));
                Canvas canvasTmp = new Canvas(this.rubber);
                canvasTmp.drawCircle((float) this.eraserHalf, (float) this.eraserHalf, (float) this.eraserHalf, circlePaint);
                this.handWritingCanvas = new HandWritingCanvas(this.mWidth, this.mHeight);
            }
        } else {
            if (HandWritingViewHelper.DEBUG) {
                XHLog.i(TAG, "mWidth or mHeight is 0!!!", new Object[0]);
            }

        }
    }

    private void initHandViewObserver() {
        this.onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
            public void onGlobalLayout() {
                MyHandWritingCoreView.this.mWidth = MyHandWritingCoreView.this.getWidth();
                MyHandWritingCoreView.this.mHeight = MyHandWritingCoreView.this.getHeight();
                if (HandWritingViewHelper.DEBUG) {
                    XHLog.i(MyHandWritingCoreView.TAG, "onGlobalLayout() >>> mWidth=" + MyHandWritingCoreView.this.mWidth + ", mHeight=" + MyHandWritingCoreView.this.mHeight, new Object[0]);
                }

                if (MyHandWritingCoreView.this.mWidth > 0 && MyHandWritingCoreView.this.mHeight > 0 && MyHandWritingCoreView.this.getViewTreeObserver().isAlive()) {
                    MyHandWritingCoreView.this.initBitmapCanvasBitmapPaint();
                    MyHandWritingCoreView.this.getViewTreeObserver().removeGlobalOnLayoutListener(MyHandWritingCoreView.this.onGlobalLayoutListener);
                }

            }
        };
        this.getViewTreeObserver().addOnGlobalLayoutListener(this.onGlobalLayoutListener);
    }

    public void closeHandWrite() {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "closeHandWrite", new Object[0]);
        }

        this.setCanDraw(false);
    }

    public void openHandWrite() {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "openHandWrite", new Object[0]);
        }

        this.setCanDraw(true);
    }

    public void setToWriting() {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "setToWriting", new Object[0]);
        }

        if (this.mIsRubber) {
            this.setToWritingInside();
            //  this.listToStrokes(true);
        }
    }

    private void setToWritingInside() {
        if (this.mIsRubber) {
            if (this.mPaint != null) {
                this.mIsRubber = false;
                this.mPaint.setStrokeWidth(2.0F);
                this.mPaint.setXfermode((Xfermode) null);
                this.setDrawType(this.mDrawType);
            }

        }
    }

    public void setToRubber() {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "setToRubber", new Object[0]);
        }

        if (!this.mIsRubber) {
            this.onSaveEditView(this.mDrawType);
            this.setToRubberInside();
            if (HandWritingViewHelper.DEBUG) {
                //  XHLog.i(TAG, "this.strokes.toString()=" + this.strokes.toString(), new Object[0]);
            }

            //   this.strokesToList(this.strokes.toString());
        }
    }

    private void setToRubberInside() {
        if (!this.mIsRubber) {
            if (this.mPaint != null) {
                this.mIsRubber = true;
                this.mPaint.setStrokeWidth(2.0F);
                this.mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
                this.mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
                this.mPaint.setPathEffect((PathEffect) null);
            }

        }
    }

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "onMeasure >>> getWidth:" + this.getWidth() + ",getHeight:" + this.getHeight(), new Object[0]);
        }

    }

    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "onLayout() >>> changed:" + changed + ", width:" + this.getWidth() + ", height:" + this.getHeight(), new Object[0]);
        }

        if (changed) {
            this.mWidth = this.getWidth();
            this.mHeight = this.getHeight();
            this.initBitmapCanvasBitmapPaint();
            String strokesString = this.getStrokesString();
            if (!TextUtils.isEmpty(strokesString)) {
                this.restoreToImage(strokesString);
            }
        }

    }

    public boolean onTouchEvent(MotionEvent event) {
        if (!this.canDraw) {
            return false;
        } else {
            int toolType = event.getToolType(0);
            if (toolType == MotionEvent.TOOL_TYPE_STYLUS) {//手写笔触摸
                if (HandWritingViewHelper.DEBUG) {
                    XHLog.i(TAG, "input toolType == TOOL_TYPE_STYLUS", new Object[0]);
                }
            } else {
                if (!HandWritingViewHelper.isSpecialDevice()) {
                    if (this.actionDownView != null) {
                        this.actionDownView.dispatchTouchEvent(event);
                    }

                    Log.e("jc", "coreview");
                    return false;
                }

                if (HandWritingViewHelper.DEBUG) {
                    XHLog.i(TAG, "isSpecialDevice() == true!!!", new Object[0]);
                }
            }

            boolean result = this.handleTouchEvent(event);
            if (this.motionEventCallback != null) {
                this.motionEventCallback.onTouchEvent(event);
            }

            return result;
        }
    }

    private boolean handleTouchEvent(MotionEvent event) {
        float pressure = this.obtainPressure(event);
        int x = (int) event.getX();
        int y = (int) event.getY();
        if (x < 0) {
            x = 0;
        }

        if (y < 0) {
            y = 0;
        }

        switch (event.getActionMasked()) {

            case MotionEvent.ACTION_DOWN:
                if (HandWritingViewHelper.DEBUG) {
                    XHLog.i(TAG, "mIsGeometryEditable = [" + this.mIsGeometryEditable + "]", new Object[0]);
                }

                if (!this.mIsGeometryEditable || x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY) {
                    this.mIsDispatch = true;
                    this.handleActionDown(event, pressure, x, y);
                    this.disableScrollImpl();
                    Log.e("刷新6","刷新中");
                    this.invalidate();
                    break;
                }

                Toast.makeText(this.getContext(), "编辑状态下的几何图形尚未保存,请先保存!", Toast.LENGTH_SHORT).show();
                return false;
            case MotionEvent.ACTION_UP:
                this.mIsDispatch = true;
                this.handleActionUp(event, pressure, x, y);
                this.enableScrollImpl();
                this.invalidate();
                Log.e("刷新1","刷新中");
                break;
            case MotionEvent.ACTION_MOVE:
                if (this.mIsDispatch) {
                    this.handleActionMove(pressure, x, y);
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                this.mIsDispatch = true;
                this.handleActionCancel(event, x, y);
                this.disableScrollImpl();
                this.invalidate();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                this.mIsDispatch = false;
                this.enableScrollImpl();
                return false;
            case 211:
                Log.e("刷新3","刷新中");
                this.handleAction211(x, y);
                this.invalidate();
                break;
            case 212:
                Log.e("刷新4","刷新中");
                this.handleAction212(x, y);
                this.invalidate();
                break;
            case 213:
                this.handleAction213(x, y);
                this.invalidate();
        }


        return true;
    }

    private float obtainPressure(MotionEvent event) {
        float pressure = MathArithmetic.lerp(this.lastPressure, event.getPressure(), 0.15F);
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "lastPressure_" + this.lastPressure + ", pressure_" + pressure, new Object[0]);
        }

        if (pressure > 0.9F) {
            pressure = 0.9F;
        }

        this.lastPressure = pressure;
        return pressure;
    }

    private void disableScrollImpl() {
        ViewParent parent = this.getParent();
        if (parent != null) {
            parent.requestDisallowInterceptTouchEvent(true);
        }

    }

    private void enableScrollImpl() {
        ViewParent parent = this.getParent();
        if (parent != null) {
            parent.requestDisallowInterceptTouchEvent(false);
        }

    }

    private void handleActionDown(MotionEvent event, float pressure, int x, int y) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "handleActionDown:" + x + "_" + y, new Object[0]);
        }

        this.recordStart(x, y, pressure);
        this.touchStart(x, y, pressure);
        this.mIsStrokesChanged = true;
        if (this.actionDownView != null) {
            this.actionDownView.dispatchTouchEvent(event);
        }

    }

    private void handleActionMove(float pressure, int x, int y) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "handleActionMove:" + x + "_" + y + "; old:" + this.oldX + "_" + this.oldY, new Object[0]);
        }

        if (this.isGeometryType()) {
            x = this.reviseGeometryX(x);
            y = this.reviseGeometryY(y);
        } else if (y > this.mHeight) {
            if (this.mAtomicInteger.get() == 0) {
                this.recordUp(x, this.mHeight, pressure);
                this.touchUp(x, this.mHeight, pressure);
                this.mAtomicInteger.getAndIncrement();
            }

            return;
        }

        if (this.mAtomicInteger.get() > 0) {
            this.recordStart(x, this.mHeight, pressure);
            this.touchStart(x, this.mHeight, pressure);
            this.mAtomicInteger.set(0);
        }

        if (this.oldX != -1 && this.oldY != -1) {
            int dx = Math.abs(x - this.oldX);
            int dy = Math.abs(y - this.oldY);
            if (dx > this.validAbs || dy > this.validAbs) {
                this.recordMove(x, y, pressure);
                this.touchMove(x, y, pressure);
                this.mIsStrokesChanged = true;
            }
        } else {
            this.recordStart(x, y, pressure);
            this.touchStart(x, y, pressure);
            this.mIsStrokesChanged = true;
        }

    }

    private void handleActionUp(MotionEvent event, float pressure, int x, int y) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "handleActionUp:" + x + "_" + y, new Object[0]);
        }

        if (this.actionDownView != null) {
            this.actionDownView.dispatchTouchEvent(event);
        }

        if (this.isGeometryType()) {
            x = this.reviseGeometryX(x);
            y = this.reviseGeometryY(y);
        } else if (this.mAtomicInteger.get() > 0) {
            this.mAtomicInteger.set(0);
            this.oldX = this.oldY = -1;
            return;
        }

        this.recordUp(x, y, pressure);
        this.touchUp(x, y, pressure);
    }

    private int reviseGeometryX(int x) {
        if (this.mGeometryListener != null) {
            int dragPointRadius = this.mGeometryListener.getDragPointRadius();
            if (x < dragPointRadius) {
                return dragPointRadius;
            }

            int tempX = this.mWidth - dragPointRadius;
            if (x > tempX) {
                return tempX;
            }
        }

        return x;
    }

    private int reviseGeometryY(int y) {
        if (this.mGeometryListener != null) {
            int limitTop = this.mGeometryListener.getLimitTop();
            if (y < limitTop) {
                return limitTop;
            }

            int tempY = this.mHeight - this.mGeometryListener.getDragPointRadius();
            if (y > tempY) {
                return tempY;
            }
        }

        return y;
    }

    private void handleActionCancel(MotionEvent event, int x, int y) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "handleActionCancel:" + x + "_" + y + "; old:" + this.oldX + "_" + this.oldY, new Object[0]);
        }

        if (this.actionDownView != null) {
            this.actionDownView.dispatchTouchEvent(event);
        }

        this.oldX = this.oldY = -1;
        if (this.mIsTempChangeRubber) {
            this.setToWriting();
        }

    }

    private void handleAction211(int x, int y) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "handleAction211:" + x + "_" + y, new Object[0]);
        }

        if (this.mGeometryListener != null) {
            this.mGeometryListener.handleEditableGeometry();
        }

        if (!this.mIsRubber) {
            this.setToRubber();
            this.mIsTempChangeRubber = true;
        } else {
            this.mIsTempChangeRubber = false;
        }

        this.isNeedRedraw = false;
        this.deleteRecord(x, y);
        this.oldX = this.endX = x;
        this.oldY = this.endY = y;
    }

    private void handleAction213(int x, int y) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "handleAction213:" + x + "_" + y, new Object[0]);
        }

        int distanceX = Math.abs(x - this.oldX);
        int distanceY = Math.abs(y - this.oldY);
        if (distanceX > this.validAbs || distanceY > this.validAbs) {
            this.deleteRecord(x, y);
            this.oldX = x;
            this.oldY = y;
            this.invalidate();
            Log.e("刷新4","刷新中");
        }

    }

    private void handleAction212(int x, int y) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "handleAction212:" + x + "_" + y, new Object[0]);
        }

        this.endX = x;
        this.endY = y;
        this.oldX = this.oldY = -1;
        if (this.mIsTempChangeRubber) {
            this.setToWriting();
        }

    }

    public boolean isInvalid(int x, int y) {
        return x <= 0 || y <= 0 || x >= this.mWidth || y >= this.mHeight;
    }

    /**
     * 按下去的时候，刚开始触摸的时候
     *
     * @param x
     * @param y
     * @param pressure
     */
    private void recordStart(int x, int y, float pressure) {
        if (this.mIsRubber) {
            this.isNeedRedraw = false;
            this.deleteRecord(x, y);
        } else {
            this.minX = x;
            this.minY = y;
            this.maxX = x;
            this.maxY = y;
            this.mStrokeWidth = Math.max(this.mStrokeWidth, x);
            this.mStrokeHeight = Math.max(this.mStrokeHeight, y);
            if (this.isGeometryType()) {
                this.recordGeometryDown();
            } else {
                Log.e(TAG, "recordStart");
                //当前没有值的情况
                //TODO  第一点的的时候修改
                strokePointInfoList.clear();
                PointInfo pointInfo = new PointInfo();

                pointInfo.x = x;
                pointInfo.y = y;
                this.strokePathInfo = new PathInfo();
                pointInfo.drawTime = System.currentTimeMillis();
                pointInfo.pressure = pressure;
                strokePointInfoList.add(pointInfo);
                strokePathInfo.drawType = this.mDrawType.getCode();
                strokePathInfo.color = this.mPaint.getColor();
                //回收
                pointInfo = null;

            }

            Log.e("recordStart", this.mDrawType.getCode() + "");
        }

    }

    private void touchStart(int x, int y, float pressure) {
        this.lastPressure = pressure;
        this.oldX = this.endX = x;
        this.oldY = this.endY = y;
        switch (this.mDrawType) {
            case CURVE:
            case DASH:
                this.mPath.reset();
                this.mPath.moveTo((float) x, (float) y);
            default:
        }
    }

    /**
     * 移动的时候
     *
     * @param x
     * @param y
     * @param pressure
     */
    private void recordMove(int x, int y, float pressure) {
        if (this.mIsRubber) {
            this.deleteRecord(x, y);
        } else {
            switch (this.mDrawType) {
                case CURVE:
                case DASH:
                    this.updateRange(x, y);
                    //TODO  滑动的时候修改
                    //  this.strokes.append(";").append(x).append(",").append(y).append(",").append(String.valueOf(System.currentTimeMillis())).append(",").append(pressure);
                    Log.e("recordMove", this.mDrawType.getCode() + "");
                    PointInfo pointInfo = new PointInfo();
                    pointInfo.x = x;
                    pointInfo.y = y;
                    pointInfo.drawTime = System.currentTimeMillis();
                    pointInfo.pressure = pressure;
                    strokePointInfoList.add(pointInfo);
                    //回收
                    pointInfo = null;
            }
        }

    }

    private void touchMove(int x, int y, float pressure) {
        if (this.mIsRubber) {
            this.oldX = x;
            this.oldY = y;
            Log.e("刷新1","刷新");
            this.postInvalidate();
        } else {
            switch (this.mDrawType) {
                case CURVE:
                case DASH:
                    this.drawMovePath(pressure);
                    this.mPath.quadTo((float) this.oldX, (float) this.oldY, (float) ((x + this.oldX) / 2), (float) ((y + this.oldY) / 2));
                    this.oldX = x;
                    this.oldY = y;
                    break;
                default:
                    this.endX = x;
                    this.endY = y;
                  //  this.postInvalidate();
                    Log.e("刷新2","刷新");
            }
        }

    }

    /**
     * 抬起的时候
     *
     * @param x
     * @param y
     * @param pressure
     */
    private void recordUp(int x, int y, float pressure) {
        if (this.mIsRubber) {
            this.deleteRecord(x, y);
            if (this.isNeedRedraw) {
                if (this.handWritingCanvas != null) {
                    this.handWritingCanvas.clearCanvas();
                }

                this.restorePoints();
                this.isNeedRedraw = false;
            }
        } else {
            this.updateRange(x, y);
            if (this.isGeometryType()) {
                this.recordGeometryUp();
            } else {

                //     this.strokes.append(";").append(x).append(",").append(y).append(",").append(String.valueOf(System.currentTimeMillis())).append(",").append(pressure);
                //   this.strokes.append("#").append(this.minX).append(",").append(this.minY).append(",").append(this.maxX).append(",").append(String.valueOf(System.currentTimeMillis())).append(",").append(this.maxY);
                Log.e("recordUp", this.mDrawType.getCode() + "");
                //TODO 抬起手的修改
                PointInfo pointInfo = new PointInfo();
                pointInfo.x = x;
                pointInfo.y = y;
                strokePathInfo.left = this.minX;
                strokePathInfo.top = this.minY;
                strokePathInfo.right = this.maxX;
                strokePathInfo.bottom = this.maxY;
                pointInfo.drawTime = System.currentTimeMillis();
                pointInfo.pressure = pressure;
                strokePointInfoList.add(pointInfo);
                if (strokePathInfo.pointsList == null) {
                    strokePathInfo.pointsList = new ArrayList<>();
                    strokePathInfo.pointsList.addAll(strokePointInfoList);
                } else {
                    strokePathInfo.pointsList.addAll(strokePointInfoList);
                }

                strokeList.put(indexStroke, strokePathInfo);
                indexStroke++;
                //回收
                pointInfo = null;
            }
        }

    }

    private void touchUp(int x, int y, float pressure) {
        this.endX = x;
        this.endY = y;
        if (!this.mIsRubber) {
            if (this.isGeometryType()) {
                if (this.mIsGeometryEditable && this.mGeometryListener != null) {
                    this.mGeometryListener.onShowEditGeometry(this.mGeometryTempInfo, this.mGeometryPaint, this.mDrawType);
                } else {
                    this.drawGeometryBitmap(this.mDrawType);
                }
            } else {
                switch (this.mDrawType) {
                    case CURVE:
                    case DASH:
                        this.mPath.quadTo((float) this.oldX, (float) this.oldY, (float) ((x + this.oldX) / 2), (float) ((y + this.oldY) / 2));
                        this.mPath.quadTo((float) ((x + this.oldX) / 2), (float) ((y + this.oldY) / 2), (float) x, (float) y);
                        this.drawMovePath(pressure);
                        this.lastLength = 0.0F;
                        this.mPath.reset();
                        break;
                    case LINE:
                    case DASHLINE:
                        this.drawLine((Canvas) null, (float) this.oldX, (float) this.oldY, (float) x, (float) y);
                        break;
                    case ARROW:
                        this.drawAL((Canvas) null, (float) this.oldX, (float) this.oldY, (float) x, (float) y);
                }
            }
        }

        this.oldX = this.oldY = -1;
    }

    protected void onDraw(Canvas canvas) {
        Log.e("ondraw","ondraw");
        this.mPaint.setXfermode((Xfermode) null);
        if (this.handWritingCanvas != null) {
            this.handWritingCanvas.drawCanvas(canvas, this.mBitmapPaint);
        }

        if (this.oldX != -1) {
            if (!this.mIsRubber) {
                switch (this.mDrawType) {
                    case CURVE:
                    case DASH:
                    default:
                        break;
                    case LINE:
                    case DASHLINE:
                        this.drawLine(canvas, (float) this.oldX, (float) this.oldY, (float) this.endX, (float) this.endY);
                        break;
                    case ARROW:
                        this.drawAL(canvas, (float) this.oldX, (float) this.oldY, (float) this.endX, (float) this.endY);
                        break;
                    case ISOSCELESTRIANGLE://等腰三角形
                        this.drawIsoscelesTriangle(canvas, (float) this.oldX, (float) this.oldY, (float) this.endX, (float) this.endY);
                        break;
                    case RHOMBUS://菱形
                        this.drawRhombus(canvas, (float) this.oldX, (float) this.oldY, (float) this.endX, (float) this.endY);
                        break;
                    case TRIANGLE:
                        this.drawTriangle(canvas, (float) this.oldX, (float) this.oldY, (float) this.endX, (float) this.endY);
                        break;
                    case RECTANGLE:
                        this.drawRectangle(canvas, this.oldX, this.oldY, this.endX, this.endY);
                        break;
                    case TRAPEZIUM:
                        this.drawTrapezium(canvas, this.oldX, this.oldY, this.endX, this.endY);
                        break;
                    case PARALLELOGRAM://平行四边形
                        this.drawParallelogram(canvas, this.oldX, this.oldY, this.endX, this.endY);
                        break;
                    case OVAL:
                        this.drawOval(canvas, this.oldX, this.oldY, this.endX, this.endY);
                        break;
                    case COORDINATE:
                        this.drawCoordinate(canvas, this.oldX, this.oldY, this.endX, this.endY);
                        break;
                    case NUMBER_AXIS:
                        this.drawNumberAxis(canvas, this.oldX, this.oldY, this.endX, this.endY);
                        break;
                }
            } else {
                canvas.drawBitmap(this.rubber, (float) (this.oldX - this.eraserHalf), (float) (this.oldY - this.eraserHalf), this.paintDither);
            }
        }

    }

    private void drawLine(Canvas canvas, float fromX, float fromY, float toX, float toY) {
        this.linePath.reset();
        this.linePath.moveTo(fromX, fromY);
        this.linePath.lineTo(toX, toY);
        this.linePath.close();
        if (canvas == null) {
            if (this.handWritingCanvas != null) {
                this.handWritingCanvas.drawPath(this.linePath, this.mPaint, 2.0F);
            }

        } else {
            canvas.drawPath(this.linePath, this.mPaint);
        }
    }

    private void drawAL(Canvas canvas, float sx, float sy, float ex, float ey) {
        Path path = this.obtainALPath((Path) null, sx, sy, ex, ey, 16.0F, 7.0F);
        if (canvas == null) {
            if (this.handWritingCanvas != null) {
                this.handWritingCanvas.drawPath(path, this.mPaint, 2.0F);
            }
        } else {
            canvas.drawPath(path, this.mPaint);
        }

    }

    private void drawGeometryBitmap(DrawType drawType) {
        switch (drawType) {
            case ISOSCELESTRIANGLE:
            case TRIANGLE:
            case TRAPEZIUM:
            case RHOMBUS://菱形
            case PARALLELOGRAM://平行四边形
                if (this.mGeometryTempInfo != null) {
                    this.drawTriangleOrTrapezium(this.mGeometryTempInfo.pointsList);
                }
                break;
            case RECTANGLE:
                this.drawRectangle(this.mGeometryTempInfo);
                break;
            case OVAL:
                this.drawOval(this.mGeometryTempInfo);
                break;
            case COORDINATE:
                this.drawCoordinate(this.mGeometryTempInfo);
                break;
            case NUMBER_AXIS:
                this.drawNumberAxis(this.mGeometryTempInfo);
        }

    }


    // 画几何图形---------------------------------------------------------------------------------------------------------------

    private void drawTriangle(@NonNull Canvas canvas, float fromX, float fromY, float toX, float toY) {
        this.initGeometryPath();
        this.mGeometryPath.moveTo(fromX, fromY);
//       this.mGeometryPath.lineTo(fromX - (toX - fromX), toY);
        this.mGeometryPath.lineTo(fromX, toY);
        this.mGeometryPath.lineTo(toX, toY);
        this.mGeometryPath.close();
        canvas.drawPath(this.mGeometryPath, this.mGeometryPaint);
    }

    /**
     * 画等腰三角形
     *
     * @param canvas
     * @param fromX
     * @param fromY
     * @param toX
     * @param toY
     */
    private void drawIsoscelesTriangle(@NonNull Canvas canvas, float fromX, float fromY, float toX, float toY) {
        this.initGeometryPath();
        this.mGeometryPath.moveTo(fromX, Math.max(fromY, toY));
        this.mGeometryPath.lineTo((fromX + toX) / 2, Math.min(fromY, toY));
        this.mGeometryPath.lineTo(toX, Math.max(fromY, toY));
//        this.mGeometryPath.lineTo(toX, toY);
        //  this.mGeometryPath.lineTo(fromX, toY);
        // this.mGeometryPath.lineTo(fromX - (toX - fromX), toY);
//        this.mGeometryPath.lineTo(toX, toY);
        this.mGeometryPath.close();
        canvas.drawPath(this.mGeometryPath, this.mGeometryPaint);
    }

    /**
     * 画菱形
     *
     * @param canvas
     * @param fromX
     * @param fromY
     * @param toX
     * @param toY
     */
    private void drawRhombus(@NonNull Canvas canvas, float fromX, float fromY, float toX, float toY) {
        this.initGeometryPath();
        this.mGeometryPath.moveTo(fromX, (fromY + toY) / 2);
        this.mGeometryPath.lineTo((fromX + toX) / 2, toY);
        this.mGeometryPath.lineTo(toX, (fromY + toY) / 2);
        this.mGeometryPath.lineTo((fromX + toX) / 2, fromY);
        this.mGeometryPath.close();
        canvas.drawPath(this.mGeometryPath, this.mGeometryPaint);
    }

    private void drawTriangleOrTrapezium(List<PointInfo> pointInfoList) {
        if (this.handWritingCanvas != null && pointInfoList != null && pointInfoList.size() != 0) {
            this.initGeometryPath();
            int i = 0;

            for (int pointsListSize = pointInfoList.size(); i < pointsListSize; ++i) {
                PointInfo pointInfo = (PointInfo) pointInfoList.get(i);
                if (i == 0) {
                    this.mGeometryPath.moveTo((float) pointInfo.x, (float) pointInfo.y);
                } else {
                    this.mGeometryPath.lineTo((float) pointInfo.x, (float) pointInfo.y);
                }
            }

            this.mGeometryPath.close();
            this.handWritingCanvas.drawPath(this.mGeometryPath, this.mGeometryPaint, this.mGeometryPaint.getStrokeWidth());
        }
    }

    private void drawRectangle(@NonNull Canvas canvas, int oldX, int oldY, int endX, int endY) {
        this.initGeometryPath();
        RectF rectF = new RectF((float) Math.min(oldX, endX), (float) Math.min(oldY, endY), (float) Math.max(oldX, endX), (float) Math.max(oldY, endY));
        this.mGeometryPath.addRect(rectF, Path.Direction.CW);
        canvas.drawPath(this.mGeometryPath, this.mGeometryPaint);
    }

    private void drawRectangle(PathInfo pathInfo) {
        if (this.handWritingCanvas != null && pathInfo != null) {
            this.initGeometryPath();
            RectF rectF = new RectF((float) pathInfo.left, (float) pathInfo.top, (float) pathInfo.right, (float) pathInfo.bottom);
            this.mGeometryPath.addRect(rectF, Path.Direction.CW);
            this.handWritingCanvas.drawPath(this.mGeometryPath, this.mGeometryPaint, this.mGeometryPaint.getStrokeWidth());
        }
    }

    private void drawTrapezium(@NonNull Canvas canvas, int oldX, int oldY, int endX, int endY) {
        int minX = Math.min(oldX, endX);
        int minY = Math.min(oldY, endY);
        int maxX = Math.max(oldX, endX);
        int maxY = Math.max(oldY, endY);
        int offsetX = (maxX - minX) / 4;
        this.initGeometryPath();
        this.mGeometryPath.moveTo((float) (minX + offsetX), (float) minY);
        this.mGeometryPath.lineTo((float) (maxX - offsetX), (float) minY);
        this.mGeometryPath.lineTo((float) maxX, (float) maxY);
        this.mGeometryPath.lineTo((float) minX, (float) maxY);
        this.mGeometryPath.close();
        canvas.drawPath(this.mGeometryPath, this.mGeometryPaint);
    }

    //平行四边形
    private void drawParallelogram(@NonNull Canvas canvas, int oldX, int oldY, int endX, int endY) {
        int minX = Math.min(oldX, endX);
        int minY = Math.min(oldY, endY);
        int maxX = Math.max(oldX, endX);
        int maxY = Math.max(oldY, endY);
        int offsetX = (maxX - minX) / 4;
        this.initGeometryPath();
        this.mGeometryPath.moveTo((float) (minX + offsetX), (float) minY);
        this.mGeometryPath.lineTo((float) maxX, (float) minY);
        this.mGeometryPath.lineTo((float) (maxX - offsetX), (float) maxY);
        this.mGeometryPath.lineTo((float) minX, (float) maxY);
        this.mGeometryPath.close();
        canvas.drawPath(this.mGeometryPath, this.mGeometryPaint);
    }

    private void drawOval(@NonNull Canvas canvas, int oldX, int oldY, int endX, int endY) {
        this.initGeometryPath();
        RectF rectF = new RectF((float) oldX, (float) oldY, (float) endX, (float) endY);
        this.mGeometryPath.addOval(rectF, Path.Direction.CW);
        canvas.drawPath(this.mGeometryPath, this.mGeometryPaint);
    }

    private void drawOval(PathInfo pathInfo) {
        if (this.handWritingCanvas != null && pathInfo != null) {
            this.initGeometryPath();
            RectF rectF = new RectF((float) pathInfo.left, (float) pathInfo.top, (float) pathInfo.right, (float) pathInfo.bottom);
            this.mGeometryPath.addOval(rectF, Path.Direction.CW);
            this.handWritingCanvas.drawPath(this.mGeometryPath, this.mGeometryPaint, this.mGeometryPaint.getStrokeWidth());
        }
    }

    private void drawCoordinate(@NonNull Canvas canvas, int oldX, int oldY, int endX, int endY) {
        int minX = Math.min(oldX, endX);
        int maxX = Math.max(oldX, endX);
        int minY = Math.min(oldY, endY);
        int maxY = Math.max(oldY, endY);
        this.obtainCoordinatePath(this.mGeometryPath, minX, minY, maxX, maxY, (minX + maxX) / 2, (minY + maxY) / 2, 10.0F, 4.0F);
        canvas.drawPath(this.mGeometryPath, this.mGeometryPaint);
    }

    private void drawCoordinate(PathInfo pathInfo) {
        if (this.handWritingCanvas != null && pathInfo != null) {
            List<PointInfo> pointsList = pathInfo.pointsList;
            if (pointsList != null && pointsList.size() == 5) {
                PointInfo pointInfo = (PointInfo) pointsList.get(4);
                this.obtainCoordinatePath(this.mGeometryPath, pathInfo.left, pathInfo.top, pathInfo.right, pathInfo.bottom, pointInfo.x, pointInfo.y, 10.0F, 4.0F);
                Paint.Style tempStyle = this.mGeometryPaint.getStyle();
                if (tempStyle != Paint.Style.FILL_AND_STROKE) {
                    this.mGeometryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
                }

                this.handWritingCanvas.drawPath(this.mGeometryPath, this.mGeometryPaint, this.mGeometryPaint.getStrokeWidth());
                this.mGeometryPaint.setStyle(tempStyle);
            }
        }
    }

    private void drawNumberAxis(@NonNull Canvas canvas, int oldX, int oldY, int endX, int endY) {
        int minX = Math.min(oldX, endX);
        int maxX = Math.max(oldX, endX);
        int minY = Math.min(oldY, endY);
        int maxY = Math.max(oldY, endY);
        this.obtainNumberAxisPath(this.mGeometryPath, minX, maxX, (minX + maxX) / 2, (minY + maxY) / 2, 10.0F, 4.0F);
        canvas.drawPath(this.mGeometryPath, this.mGeometryPaint);
    }

    private void drawNumberAxis(PathInfo pathInfo) {
        if (this.handWritingCanvas != null && pathInfo != null) {
            if (pathInfo.pointsList != null && pathInfo.pointsList.size() == 3) {
                PointInfo originInfo = (PointInfo) pathInfo.pointsList.get(2);
                this.obtainNumberAxisPath(this.mGeometryPath, pathInfo.left, pathInfo.right, originInfo.x, originInfo.y, 10.0F, 4.0F);
                Paint.Style tempStyle = this.mGeometryPaint.getStyle();
                if (tempStyle != Paint.Style.FILL_AND_STROKE) {
                    this.mGeometryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
                }

                this.handWritingCanvas.drawPath(this.mGeometryPath, this.mGeometryPaint, this.mGeometryPaint.getStrokeWidth());
                this.mGeometryPaint.setStyle(tempStyle);
            }
        }
    }

    // -------------------------画几何图形结束-------------------------------------------------------------


    private void initGeometryPath() {
        if (this.mGeometryPath == null) {
            this.mGeometryPath = new Path();
        } else {
            this.mGeometryPath.reset();
        }

    }

    private void drawMovePath(float pressure) {
        this.tilePath.reset();
        float penSize;
        if (pressure <= 0.0F) {
            penSize = 2.0F;
        } else {
            penSize = 1.0F + pressure * 1.5F;
        }

        this.drawTilePath(penSize);
        this.lastPressure = pressure;
    }

    private float drawTilePath(float penSize) {
        this.pathMeasure.setPath(this.mPath, false);
        float length = this.pathMeasure.getLength();
        this.pathMeasure.getSegment(this.lastLength, length, this.tilePath, true);
        if (this.handWritingCanvas != null) {
            this.handWritingCanvas.drawPath(this.tilePath, this.mPaint, penSize);
        }

        this.lastLength = length;
        float halfWidth = penSize / 2.0F;
        Log.e("drawTilePath","drawTilePath");
        this.invalidate((int) ((float) this.minX - halfWidth), (int) ((float) this.minY - halfWidth), (int) ((float) this.maxX + halfWidth), (int) ((float) this.maxY + halfWidth));
        return length;
    }

    private void updateRange(int x, int y) {
        this.minX = Math.min(this.minX, x);
        this.minY = Math.min(this.minY, y);
        this.maxX = Math.max(this.maxX, x);
        this.maxY = Math.max(this.maxY, y);
        this.mStrokeWidth = Math.max(this.mStrokeWidth, x);
        this.mStrokeHeight = Math.max(this.mStrokeHeight, y);
    }

    public void updateRange(int minX, int minY, int maxX, int maxY) {
        this.minX = minX;
        this.minY = minY;
        this.maxX = maxX;
        this.maxY = maxY;
        this.mStrokeWidth = Math.max(this.mStrokeWidth, maxX);
        this.mStrokeHeight = Math.max(this.mStrokeHeight, maxY);
    }

    public Path obtainCoordinatePath(@NonNull Path path, int minX, int minY, int maxX, int maxY, int originX, int originY, float arrowHeight, float arrowHalf) {
        int unit = this.mAxisUnit;
        path.reset();
        path = this.obtainALPath(path, (float) minX, (float) originY, (float) maxX, (float) originY, arrowHeight, arrowHalf);
        this.obtainALPath(path, (float) originX, (float) maxY, (float) originX, (float) minY, arrowHeight, arrowHalf);
        path.addCircle((float) originX, (float) originY, arrowHalf, Path.Direction.CCW);
        int halfAxisX = maxX - originX;
        int halfCount = halfAxisX / unit;

        int halfAxisY;
        int i;
        int offset;
        for (halfAxisY = 0; halfAxisY < halfCount; ++halfAxisY) {
            i = halfAxisY + 1;
            offset = originX + i * unit;
            path.moveTo((float) offset, (float) originY - arrowHalf);
            path.lineTo((float) offset, (float) originY);
        }

        halfAxisX = originX - minX;
        halfCount = halfAxisX / unit;

        for (halfAxisY = 0; halfAxisY < halfCount; ++halfAxisY) {
            i = halfAxisY + 1;
            offset = originX - i * unit;
            path.moveTo((float) offset, (float) originY - arrowHalf);
            path.lineTo((float) offset, (float) originY);
        }

        halfAxisY = originY - minY;
        halfCount = halfAxisY / unit;

        int minusY;
        for (i = 0; i < halfCount; ++i) {
            offset = i + 1;
            minusY = originY - offset * unit;
            path.moveTo((float) originX + arrowHalf, (float) minusY);
            path.lineTo((float) originX, (float) minusY);
        }

        halfAxisY = maxY - originY;
        halfCount = halfAxisY / unit;

        for (i = 0; i < halfCount; ++i) {
            offset = i + 1;
            minusY = originY + offset * unit;
            path.moveTo((float) originX + arrowHalf, (float) minusY);
            path.lineTo((float) originX, (float) minusY);
        }

        return path;
    }

    public Path obtainNumberAxisPath(@NonNull Path path, int minX, int maxX, int originX, int originY, float arrowHeight, float arrowHalf) {
        int unit = this.mAxisUnit;
        path.reset();
        this.obtainALPath(path, (float) minX, (float) originY, (float) maxX, (float) originY, arrowHeight, arrowHalf);
        path.addCircle((float) originX, (float) originY, arrowHalf, Path.Direction.CCW);
        int halfAxisX = maxX - originX;
        int halfCount = halfAxisX / unit;

        int i;
        int offset;
        int minusX;
        for (i = 0; i < halfCount; ++i) {
            offset = i + 1;
            minusX = originX + offset * unit;
            path.moveTo((float) minusX, (float) originY - arrowHalf);
            path.lineTo((float) minusX, (float) originY);
        }

        halfAxisX = originX - minX;
        halfCount = halfAxisX / unit;

        for (i = 0; i < halfCount; ++i) {
            offset = i + 1;
            minusX = originX - offset * unit;
            path.moveTo((float) minusX, (float) originY - arrowHalf);
            path.lineTo((float) minusX, (float) originY);
        }

        return path;
    }

    private Path obtainALPath(Path path, float sx, float sy, float ex, float ey, float arrowHeight, float arrowHalf) {
        double arrowAngle = Math.atan((double) (arrowHalf / arrowHeight));
        double arrowLen = Math.sqrt((double) (arrowHalf * arrowHalf + arrowHeight * arrowHeight));
        double[] arrXY1 = MathArithmetic.rotateVec(ex - sx, ey - sy, arrowAngle, true, arrowLen);
        double[] arrXY2 = MathArithmetic.rotateVec(ex - sx, ey - sy, -arrowAngle, true, arrowLen);
        int x3 = (int) ((double) ex - arrXY1[0]);
        int y3 = (int) ((double) ey - arrXY1[1]);
        int x4 = (int) ((double) ex - arrXY2[0]);
        int y4 = (int) ((double) ey - arrXY2[1]);
        if (path == null) {
            path = new Path();
        }

        if (x3 == 0 && y3 == 0 && x4 == 0 && y4 == 0) {
            return path;
        } else {
            path.moveTo(ex, ey);
            path.lineTo((float) x3, (float) y3);
            path.lineTo((float) x4, (float) y4);
            path.close();
            path.moveTo(sx, sy);
            path.lineTo(ex, ey);
            return path;
        }
    }

    public boolean onCancelEditView() {
        if (this.mIsGeometryEditable) {
            this.mIsGeometryEditable = false;
            return true;
        } else {
            this.mGeometryTempInfo = null;
            return false;
        }
    }

    public boolean onSaveEditView(DrawType drawType) {
        Log.e(TAG, "onSaveEditView");
        if (this.mIsGeometryEditable) {
            this.mIsGeometryEditable = false;
            this.updateGeometryPathInfo();
            // this.appendGeometryStrokes();
            this.drawGeometryBitmap(drawType);
            this.mGeometryTempInfo = null;
            this.mIsStrokesChanged = true;
            return true;
        } else {
            return false;
        }
    }

    private void recordGeometryDown() {
        this.mGeometryTempInfo = new PathInfo();
    }

    private void recordGeometryUp() {
        if (this.mGeometryListener != null && this.mGeometryListener.isGeometryInvalid(this.mDrawType, this.minX, this.minY, this.maxX, this.maxY)) {
            if (HandWritingViewHelper.DEBUG) {
                XHLog.i(TAG, "invalid Geometry!!!", new Object[0]);
            }

            this.mIsGeometryEditable = false;
            this.mGeometryTempInfo = null;
        } else {
            this.mGeometryTempInfo.color = this.mGeometryPaint.getColor();
            this.mGeometryTempInfo.drawType = this.mDrawType.getCode();
            switch (this.mDrawType) {
                //等腰
                case ISOSCELESTRIANGLE:
                    this.mGeometryTempInfo.pointsList = this.recordGeometryIsoscelesTriangle();
                    break;
                case RHOMBUS://菱形
                    this.mGeometryTempInfo.pointsList = this.recordGeometryRhombus();
                    break;
                case TRIANGLE:
                    this.mGeometryTempInfo.pointsList = this.recordGeometryTriangle();
                    break;
                case RECTANGLE:
                case OVAL:
                    this.mGeometryTempInfo.pointsList = this.recordGeometryOvalOrRec();
                    break;
                case TRAPEZIUM:
                    this.mGeometryTempInfo.pointsList = this.recordGeometryTrapezium();
                    break;
                case PARALLELOGRAM://平行四边形
                    this.mGeometryTempInfo.pointsList = this.recordGeometryParallelogram();
                    break;
                case COORDINATE:
                    this.mGeometryTempInfo.pointsList = this.recordGeometryCoordinate();
                    break;
                case NUMBER_AXIS:
                    this.mGeometryTempInfo.pointsList = this.recordGeometryNumberAxis();
                    break;
            }

            this.mGeometryTempInfo.left = this.minX;
            this.mGeometryTempInfo.top = this.minY;
            this.mGeometryTempInfo.right = this.maxX;
            this.mGeometryTempInfo.bottom = this.maxY;
            this.updateGeometryPathInfo();
            if (this.mGeometryListener != null) {
                this.mIsGeometryEditable = true;
            } else {
                this.mIsGeometryEditable = false;
                // this.appendGeometryStrokes();
            }

        }
    }

    private List<PointInfo> recordGeometryTriangle() {
        List<PointInfo> pointsList = new ArrayList(3);
        pointsList.add(this.obtainGeometryPoint(this.oldX, this.oldY, 0));
        pointsList.add(this.obtainGeometryPoint(this.oldX, this.endY, 1));
        pointsList.add(this.obtainGeometryPoint(this.endX, this.endY, 2));
        return pointsList;
    }

    /**
     * 保存画几何图形的位置
     * this.mGeometryPath.moveTo(fromX, fromY);
     * this.mGeometryPath.lineTo(toX, toY);
     * this.mGeometryPath.lineTo(fromX - (toX - fromX), toY);
     *
     * @return
     */
    private List<PointInfo> recordGeometryIsoscelesTriangle() {
        List<PointInfo> pointsList = new ArrayList(3);
        pointsList.add(this.obtainGeometryPoint(this.oldX, Math.max(this.oldY, this.endY), 0));
        pointsList.add(this.obtainGeometryPoint((this.oldX + this.endX) / 2, Math.min(this.oldY, this.endY), 1));
        pointsList.add(this.obtainGeometryPoint(this.endX, Math.max(this.oldY, this.endY), 2));
        return pointsList;
    }

    private List<PointInfo> recordGeometryRhombus() {
        List<PointInfo> pointsList = new ArrayList(4);
        pointsList.add(this.obtainGeometryPoint(this.oldX, (this.oldY + this.endY) / 2, 0));
        pointsList.add(this.obtainGeometryPoint((this.oldX + this.endX) / 2, this.endY, 1));
        pointsList.add(this.obtainGeometryPoint(this.endX, (this.oldY + this.endY) / 2, 2));
        pointsList.add(this.obtainGeometryPoint((this.oldX + this.endX) / 2, this.oldY, 3));
        return pointsList;
    }


    private List<PointInfo> recordGeometryOvalOrRec() {
        List<PointInfo> pointsList = new ArrayList(4);
        pointsList.add(this.obtainGeometryPoint(this.minX, this.minY, 0, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(this.maxX, this.minY, 1, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(this.maxX, this.maxY, 2, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(this.minX, this.maxY, 3, System.currentTimeMillis()));
        return pointsList;
    }

    private List<PointInfo> recordGeometryTrapezium() {
        List<PointInfo> pointsList = new ArrayList(4);
        int offsetX = (this.maxX - this.minX) / 4;
        pointsList.add(this.obtainGeometryPoint(this.minX + offsetX, this.minY, 0, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(this.maxX - offsetX, this.minY, 1, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(this.maxX, this.maxY, 2, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(this.minX, this.maxY, 3, System.currentTimeMillis()));
        return pointsList;
    }

    //平行四边形
    private List<PointInfo> recordGeometryParallelogram() {
        List<PointInfo> pointsList = new ArrayList(4);
        int offsetX = (this.maxX - this.minX) / 4;
        pointsList.add(this.obtainGeometryPoint(this.minX + offsetX, this.minY, 0, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(this.maxX, this.minY, 1, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(this.maxX - offsetX, this.maxY, 2, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(this.minX, this.maxY, 3, System.currentTimeMillis()));
        return pointsList;
    }

    private List<PointInfo> recordGeometryCoordinate() {
        List<PointInfo> pointsList = new ArrayList(5);
        int dragPointDiameter;
        int disX;
        if (this.mGeometryListener != null) {
            dragPointDiameter = this.mGeometryListener.getDragPointRadius() * 2;
            int disY;
            if ((disX = this.maxX - this.minX) < dragPointDiameter) {
                disY = Math.round((float) (dragPointDiameter - disX) * 1.0F / 2.0F);
                this.minX -= disY;
                this.maxX += disY;
            }

            if ((disY = this.maxY - this.minY) < dragPointDiameter) {
                int offsetY = Math.round((float) (dragPointDiameter - disY) * 1.0F / 2.0F);
                this.minY -= offsetY;
                this.maxY += offsetY;
            }
        }

        dragPointDiameter = (this.minX + this.maxX) / 2;
        disX = (this.minY + this.maxY) / 2;
        pointsList.add(this.obtainGeometryPoint(dragPointDiameter, this.minY, 0, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(this.maxX, disX, 1, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(dragPointDiameter, this.maxY, 2, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(this.minX, disX, 3, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(dragPointDiameter, disX, -1, System.currentTimeMillis()));
        return pointsList;
    }

    private List<PointInfo> recordGeometryNumberAxis() {
        List<PointInfo> pointsList = new ArrayList(3);
        int midX = (this.minX + this.maxX) / 2;
        int midY = (this.minY + this.maxY) / 2;
        pointsList.add(this.obtainGeometryPoint(this.maxX, midY, 1, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(this.minX, midY, 3, System.currentTimeMillis()));
        pointsList.add(this.obtainGeometryPoint(midX, midY, -1, System.currentTimeMillis()));
        this.minY = midY - 4;
        this.maxY = midY + 4;
        return pointsList;
    }

    /**
     * 更新画笔
     */
    private void updateGeometryPathInfo() {
        if (this.mGeometryTempInfo != null && this.mGeometryTempInfo.pointsList != null && this.mGeometryTempInfo.pointsList.size() != 0) {
            strokePointInfoList.clear();
            strokePathInfo = new PathInfo();
            strokePathInfo.drawType = this.mGeometryTempInfo.drawType;
            strokePathInfo.color = this.mGeometryTempInfo.color;
            strokePathInfo.left = this.mGeometryTempInfo.left;
            strokePathInfo.top = this.mGeometryTempInfo.top;
            strokePathInfo.right = this.mGeometryTempInfo.right;
            strokePathInfo.bottom = this.mGeometryTempInfo.bottom;
            if (strokePathInfo.pointsList == null) {
                strokePathInfo.pointsList = new ArrayList<>();
            }
            strokePathInfo.pointsList.addAll(this.mGeometryTempInfo.pointsList);
            strokeList.put(indexStroke, strokePathInfo);
            indexStroke++;

        }
    }

    private PointInfo obtainGeometryPoint(int x, int y, int index) {
        return this.obtainGeometryPoint(x, y, index, System.currentTimeMillis());
    }

    //todo
    private PointInfo obtainGeometryPoint(int x, int y, int index, long time) {
        PointInfo pointInfo = new PointInfo();
        pointInfo.x = x;
        pointInfo.y = y;
        pointInfo.drawTime = time;
        pointInfo.index = index;
        return pointInfo;
    }

    public String getStrokes() {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "mIsStrokesChanged : " + this.mIsStrokesChanged, new Object[0]);
        }


        return this.getStrokesString();
    }

    @Nullable
    private String getStrokesString() {
        if (this.mIsRubber) {
            //  this.listToStrokes(true);
        }

        if (this.strokeList != null && this.strokeList.size() > 0) {
            String temp = this.mWidth + "," + this.mHeight + "," + this.mStrokeWidth + "," + this.mStrokeHeight + "&" + "1.0";

            return new Gson().toJson(strokeList);
        } else {
            return null;
        }
    }

    public void loadBitmap(Bitmap bitmap) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "loadBitmap", new Object[0]);
        }

        if (this.handWritingCanvas != null) {
            this.handWritingCanvas.drawBitmap(bitmap, this.mPaint);
        }

    }

    public void loadBitmap(byte[] data) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "loadBitmap", new Object[0]);
        }

        try {
            Bitmap image = BitmapFactory.decodeByteArray(data, 0, data.length);
            this.loadBitmap(image);
        } catch (Exception var4) {
            var4.printStackTrace();
        }

    }

    public String getEncodeBitmap() {
        byte[] data = this.getBitmapBytes();
        return data == null ? null : BASE64.encode(data);
    }

    public byte[] getBitmapBytes() {
        Bitmap bitmap = this.getBitmap();
        if (bitmap != null && !bitmap.isRecycled()) {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
            byte[] data = bos.toByteArray();

            try {
                bos.close();
            } catch (IOException var5) {
                var5.printStackTrace();
            }

            return data;
        } else {
            return null;
        }
    }

    public void recycleBitmap() {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "recycleBitmap", new Object[0]);
        }

        if (this.writingViewBitmap != null && !this.writingViewBitmap.isRecycled()) {
            this.writingViewBitmap.recycle();
            this.writingViewBitmap = null;
        }

    }

    private boolean checkDelete(int x, int y, int touchX, int touchY) {
        return Math.pow((double) (touchY - y), 2.0D) + Math.pow((double) (touchX - x), 2.0D) <= Math.pow((double) this.eraserHalf, 2.0D);
    }

    public boolean checkOvalDelete(int ovalX, int ovalY, int a, int b, int circleX, int circleY, int r) {
        MyHandWritingCoreView.CGPoint[] points = this.getPoint(circleX, circleY, r, ovalX, ovalY, circleX, circleY);
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "x2=" + points[0].x + "y2=" + points[0].y, new Object[0]);
            XHLog.i(TAG, "x2=" + points[1].x + "y2=" + points[1].y, new Object[0]);
        }

        return this.getValue(ovalX, ovalY, a, b, (int) points[0].x, (int) points[0].y) * this.getValue(ovalX, ovalY, a, b, (int) points[1].x, (int) points[1].y) <= 0.0F;
    }

    MyHandWritingCoreView.CGPoint[] getPoint(int cx, int cy, int r, int stx, int sty, int edx, int edy) {
        double k = (double) (edy - sty) / (double) (edx - stx);
        double b = (double) edy - k * (double) edx;
        double c = (double) (cx * cx) + (b - (double) cy) * (b - (double) cy) - (double) (r * r);
        double a = 1.0D + k * k;
        double b1 = (double) (2 * cx) - 2.0D * k * (b - (double) cy);
        double tmp = Math.sqrt(b1 * b1 - 4.0D * a * c);
        double x1 = (b1 + tmp) / (2.0D * a);
        double y1 = k * x1 + b;
        double x2 = (b1 - tmp) / (2.0D * a);
        double y2 = k * x2 + b;
        MyHandWritingCoreView.CGPoint[] p = new MyHandWritingCoreView.CGPoint[]{new MyHandWritingCoreView.CGPoint(), null};
        p[0].x = x1;
        p[0].y = y1;
        p[1] = new MyHandWritingCoreView.CGPoint();
        p[1].x = x2;
        p[1].y = y2;
        return p;
    }

    public float getValue(int ovalX, int ovalY, int a, int b, int x, int y) {
        return (float) Math.pow((double) (x - ovalX), 2.0D) / (float) Math.pow((double) a, 2.0D) + (float) Math.pow((double) (y - ovalY), 2.0D) / (float) Math.pow((double) b, 2.0D) - 1.0F;
    }

    private boolean checkDelete(PointInfo startPoint, PointInfo endPoint, int touchX, int touchY) {
        int startX = startPoint.x;
        int startY = startPoint.y;
        int endX = endPoint.x;
        int endY = endPoint.y;
        int minX = Math.min(startX, endX);
        int minY = Math.min(startY, endY);
        int maxX = Math.max(startX, endX);
        int maxY = Math.max(startY, endY);
        if (this.checkDelete(endX, endY, touchX, touchY)) {
            return true;
        } else if (this.oldX != -1 && MathArithmetic.intersect1(new Point(startX, startY), new Point(endX, endY), new Point(this.oldX, this.oldY), new Point(touchX, touchY))) {
            return true;
        } else if (touchX + this.eraserHalf >= minX && touchX - this.eraserHalf <= maxX && touchY + this.eraserHalf >= minY && touchY - this.eraserHalf <= maxY) {
            double distance = MathArithmetic.pointToLine(startX, startY, endX, endY, touchX, touchY);
            return distance <= (double) this.eraserHalf;
        } else {
            return false;
        }
    }

    private void updateRect(PathInfo pathInfo, boolean isFirst) {
        if (isFirst) {
            this.rectMinX = pathInfo.left;
            this.rectMinY = pathInfo.top;
            this.rectMaxX = pathInfo.right;
            this.rectMaxY = pathInfo.bottom;
        } else {
            this.rectMinX = Math.min(this.rectMinX, pathInfo.left);
            this.rectMinY = Math.min(this.rectMinY, pathInfo.top);
            this.rectMaxX = Math.max(this.rectMaxX, pathInfo.right);
            this.rectMaxY = Math.max(this.rectMaxY, pathInfo.bottom);
        }

    }

    private void deleteRecord(int touchX, int touchY) {
        boolean isDel = false;
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "pathsList.size()=" + this.pathsList.size(), new Object[0]);
        }

        int pointSize;
        for (int i = 0; i < this.pathsList.size(); ++i) {
            PathInfo pathInfo = (PathInfo) this.pathsList.get(i);
            List<PointInfo> pointsList = pathInfo.pointsList;
            pointSize = pointsList.size();
            if (pointSize != 0 && (touchX + this.eraserHalf >= pathInfo.left && touchY + this.eraserHalf >= pathInfo.top && touchX - this.eraserHalf <= pathInfo.right && touchY - this.eraserHalf <= pathInfo.bottom || this.oldX == -1 || MathArithmetic.intersect1(new Point(pathInfo.left, pathInfo.top), new Point(pathInfo.right, pathInfo.bottom), new Point(this.oldX, this.oldY), new Point(touchX, touchY)) || MathArithmetic.intersect1(new Point(pathInfo.left, pathInfo.bottom), new Point(pathInfo.right, pathInfo.top), new Point(this.oldX, this.oldY), new Point(touchX, touchY)))) {
                PointInfo pointInfo = (PointInfo) pointsList.get(0);
                if (this.checkDelete(pointInfo.x, pointInfo.y, touchX, touchY)) {
                    this.updateRect(pathInfo, !isDel);
                    this.pathsList.remove(i);
                    --i;
                    isDel = true;
                } else {
                    int j;
                    if (this.isDefDrawType(pathInfo.drawType, DrawType.OVAL)) {
                        j = (pathInfo.right - pathInfo.left) / 2;
                        int midY = (pathInfo.bottom - pathInfo.top) / 2;
                        if (this.checkOvalDelete(pathInfo.left + j, pathInfo.top + midY, j, midY, touchX, touchY, this.eraserHalf)) {
                            this.updateRect(pathInfo, !isDel);
                            this.pathsList.remove(i);
                            --i;
                            isDel = true;
                        }
                    } else {
                        PointInfo prePointInfo;
                        if (this.isDefDrawType(pathInfo.drawType, DrawType.COORDINATE) && pointSize == 5) {
                            PointInfo pointInfo0 = (PointInfo) pointsList.get(0);
                            prePointInfo = (PointInfo) pointsList.get(1);
                            PointInfo pointInfo2 = (PointInfo) pointsList.get(2);
                            PointInfo pointInfo3 = (PointInfo) pointsList.get(3);
                            if (this.checkDelete(pointInfo0, pointInfo2, touchX, touchY) || this.checkDelete(prePointInfo, pointInfo3, touchX, touchY)) {
                                this.updateRect(pathInfo, !isDel);
                                this.pathsList.remove(i);
                                --i;
                                isDel = true;
                            }
                        } else {
                            for (j = 1; j < pointSize; ++j) {
                                prePointInfo = (PointInfo) pointsList.get(j - 1);
                                pointInfo = (PointInfo) pointsList.get(j);
                                if (this.checkDelete(prePointInfo, pointInfo, touchX, touchY)) {
                                    this.updateRect(pathInfo, !isDel);
                                    this.pathsList.remove(i);
                                    --i;
                                    isDel = true;
                                    break;
                                }

                                if ((this.isDefDrawType(pathInfo.drawType, DrawType.TRIANGLE)
                                        || this.isDefDrawType(pathInfo.drawType, DrawType.ISOSCELESTRIANGLE)
                                        || this.isDefDrawType(pathInfo.drawType, DrawType.RECTANGLE)
                                        || this.isDefDrawType(pathInfo.drawType, DrawType.RHOMBUS) //菱形
                                        || this.isDefDrawType(pathInfo.drawType, DrawType.PARALLELOGRAM) //平行四边形
                                        || this.isDefDrawType(pathInfo.drawType, DrawType.TRAPEZIUM))
                                        && j == pointSize - 1
                                        && this.checkDelete((PointInfo) pointsList.get(0), pointInfo, touchX, touchY)) {
                                    this.updateRect(pathInfo, !isDel);
                                    this.pathsList.remove(i);
                                    --i;
                                    isDel = true;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }

        int addedValue = 18;
        if (isDel) {
            this.rectMinX -= addedValue;
            this.rectMinY -= addedValue;
            this.rectMaxX += addedValue;
            this.rectMaxY += addedValue;
            Rect mSrcRect = new Rect(this.rectMinX, this.rectMinY, this.rectMaxX, this.rectMaxY);
            this.mPaint.setStrokeWidth(2.0F);
            this.mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
            this.mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
            this.mPaint.setPathEffect((PathEffect) null);
            if (this.handWritingCanvas != null) {
                this.handWritingCanvas.drawRect(mSrcRect, this.mPaint);
            }

            if (this.pathsList.size() > 0) {
                int pathSize = this.pathsList.size();

                for (pointSize = 0; pointSize < pathSize; ++pointSize) {
                    PathInfo pathInfo = (PathInfo) this.pathsList.get(pointSize);
                    if (mSrcRect.intersects(pathInfo.left - addedValue, pathInfo.top - addedValue, pathInfo.right + addedValue, pathInfo.bottom + addedValue)) {
                        this.isNeedRedraw = true;
                        this.drawOrRecordOnePath(pathInfo, true);
                    }
                }
            }

            this.mIsStrokesChanged = true;
        }

        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "out", new Object[0]);
        }

    }

    public void change(int width, int height) {
        this.setLayoutParams(new android.widget.FrameLayout.LayoutParams(width, height));
    }

    public void restoreToImage(String str) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "restoreToImage() >>> str:" + str, new Object[0]);
        }

        this.clear();
        if (!TextUtils.isEmpty(str)) {
            this.mIsStrokesChanged = false;
            //  this.restoreCanvas(str);
            //   this.postInvalidate();
            // this.cacheBitmap(str);
        }
    }

    public void restoreToImageArray(SparseArray<PathInfo> strokeList) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "restoreToImage() >>> str:" + strokeList.size(), new Object[0]);
        }

        this.clear();

        if (strokeList != null && strokeList.size() > 0) {
            this.mIsStrokesChanged = false;
            this.restoreCanvas(strokeList);

            //  this.cacheBitmap(str);
        }
    }


    /**
     * 保存的数据进行遍历根据时间进行画出来
     * TODO 还原绘画的主要逻辑
     *
     * @param strokeList
     */
    @SuppressLint("ObjectAnimatorBinding")
    private void restoreCanvas(SparseArray<PathInfo> strokeList) {
        long time=0;
        for (int i = 0; i < strokeList.size(); i++) {
            Object object = strokeList.valueAt(i);
            PathInfo pathInfo = null;
            if (object instanceof PathInfo) {
                pathInfo = (PathInfo) object;
            } else {
                pathInfo = new Gson().fromJson(object.toString(), new TypeToken<PathInfo>() {
                }.getType());
            }
            final List<PointInfo> pointInfoList = pathInfo.pointsList;
            if (pointInfoList != null && pointInfoList.size() > 0) {
                //如果是曲线才需要拆分集合，
               /* if (pathInfo.drawType == DrawType.CURVE.getCode() || pathInfo.drawType == DrawType.DASH.getCode()) {
                    if (pointInfoList.size() > 500 && pointInfoList.size() < 1000) {
                        List<List<PointInfo>> pointList = ListUtils.split(pointInfoList, 4);
                    }
                } else {*/
                boolean isRubberSrc = this.mIsRubber;
                DrawType drawTypeSrc = this.mDrawType;
                int penColorSrc = this.getPenColor();
                int geometryPenColorSrc = this.getGeometryPenColor();
                this.setToWritingInside();
                DrawType tempDrawType = DrawType.toDrawType(pathInfo.drawType);
                this.setDrawType(tempDrawType);
                if (this.isGeometryType()) {
                    this.mGeometryPaint.setColor(pathInfo.color);
                } else {
                    this.mPaint.setColor(pathInfo.color);
                }

                final Long startTime = pointInfoList.get(0).drawTime;
                final Long endTime = pointInfoList.get(pointInfoList.size() - 1).drawTime;


                final PathInfo finalPathInfo = pathInfo;

                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        /** 在这里加上线程安全锁 **/
                        synchronized (MyHandWritingCoreView.this) {
                        /** 计算出游戏一次更新的毫秒数 **/
                        /** 确保每次更新时间为50帧 **/
                         isSleep=true;
                            drawOrRecordOnePath(finalPathInfo,true);
                        }
                        Long time = endTime - startTime;
                      /*  while (time <= TIME_IN_FRAME) {
                            try {
                                Thread.sleep(20);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            time-=TIME_IN_FRAME;
                        }

                        isSleep=false;*/
                    }
                }).start();

            }
        }
    }
    /**每50帧刷新一次屏幕**/
    public static final Long TIME_IN_FRAME = 50L;
    public boolean isSleep;

    public void clear() {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "clear()", new Object[0]);
        }

        this.mStrokeWidth = 0;
        this.mStrokeHeight = 0;
        strokeList.clone();
        this.pathsList.clear();
        if (this.handWritingCanvas != null) {
            this.handWritingCanvas.clearCanvas();
        } else if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "handWritingCanvas == null!!!!", new Object[0]);
        }

        this.postInvalidate();
    }


    private Bitmap getCacheBitmap(String str) {
        return this.handWritingViewCache == null ? null : this.handWritingViewCache.getCacheBitmap(str);
    }


    private void restorePoints() {
        if (this.handWritingCanvas != null) {
            for (int i = 0; i < this.pathsList.size(); ++i) {
                this.drawOrRecordOnePath((PathInfo) this.pathsList.get(i), true);
            }

            if (!this.hasRange) {
                //  this.listToStrokes(false);
                this.mIsStrokesChanged = true;
                //this.strokesToList(this.strokes.toString());
                this.hasRange = true;
            }

        }
    }




    private void drawOrRecordOnePath(PathInfo pathInfo, boolean isDraw) {
        boolean isRubberSrc = this.mIsRubber;
        DrawType drawTypeSrc = this.mDrawType;
        int penColorSrc = this.getPenColor();
        int geometryPenColorSrc = this.getGeometryPenColor();
        this.setToWritingInside();
        DrawType tempDrawType = DrawType.toDrawType(pathInfo.drawType);
        this.setDrawType(tempDrawType);
        if (this.isGeometryType()) {
            this.mGeometryPaint.setColor(pathInfo.color);
        } else {
            this.mPaint.setColor(pathInfo.color);
        }

        List<PointInfo> pointsList = pathInfo.pointsList;
        label57:
        switch (this.mDrawType) {
            case CURVE:
            case DASH:
            case LINE:
            case DASHLINE:
            case ARROW:
            default:
                int pointSize = pointsList.size();
                int j = 0;

                while (true) {
                    if (j >= pointSize) {
                        break label57;
                    }
                    try {
                       // if(isSleep){
                            Thread.sleep(15);
                        //}
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    PointInfo pointInfo = (PointInfo) pointsList.get(j);

                    int x = pointInfo.x;
                    int y = pointInfo.y;
                    long time = pointInfo.drawTime;
                    float pressure = pointInfo.pressure;
                    if (j == 0) {
                        if (isDraw) {
                            this.touchStart(x, y, pressure);
                        } else {
                            this.recordStart(x, y, pressure);
                        }
                    } else if (j == pointSize - 1) {
                        if (isDraw) {
                            this.touchUp(x, y, pressure);
                        } else {
                            this.recordUp(x, y, pressure);
                        }
                    } else if (isDraw) {
                        this.touchMove(x, y, pressure);
                    } else {
                        this.recordMove(x, y, pressure);
                    }

                    ++j;
                }
                //等腰三角形
            case ISOSCELESTRIANGLE:
            case TRIANGLE:
            case TRAPEZIUM:
            case RHOMBUS://菱形
            case PARALLELOGRAM://平行四边形
                this.drawTriangleOrTrapezium(pointsList);
                break;
            case RECTANGLE:
                this.drawRectangle(pathInfo);
                break;
            case OVAL:
                this.drawOval(pathInfo);
                break;
            case COORDINATE:
                this.drawCoordinate(pathInfo);
                break;
            case NUMBER_AXIS:
                this.drawNumberAxis(pathInfo);
        }

        if (this.isGeometryType()) {
            if (geometryPenColorSrc != this.getGeometryPenColor()) {
                this.setGeometryPaintColor(geometryPenColorSrc);
            }
        } else if (penColorSrc != this.getPenColor()) {
            this.setPenColor(penColorSrc);
        }

        if (drawTypeSrc != this.mDrawType) {
            this.setDrawType(drawTypeSrc);
        }

        if (isRubberSrc) {
            this.setToRubberInside();
        }

    }


    public void cacheBitmap(String cacheKey) {
        if (!TextUtils.isEmpty(cacheKey)) {
            Bitmap bitmap = this.getCacheBitmap(cacheKey);
            if (bitmap == null) {
                if (this.getWidth() == 0 || this.getHeight() == 0) {
                    return;
                }

                if (this.handWritingViewCache != null) {
                    this.handWritingViewCache.putCacheBitmap(cacheKey, this.getBitmap());
                }
            }

        }
    }

    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "onAttachedToWindow()", new Object[0]);
        }

        Object view = this;

        while (true) {
            ViewParent viewParent = ((View) view).getParent();
            if (viewParent instanceof ListView) {
                ListView listView = (ListView) viewParent;
                this.setRecycleListener(listView);
                break;
            }

            if (!(viewParent instanceof View)) {
                break;
            }

            view = (View) viewParent;
        }

    }

    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        if (this.mIsGeometryEditable) {
            this.updateGeometryPathInfo();
            //  this.appendGeometryStrokes();
        }

        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "mIsGeometryEditable : " + this.mIsGeometryEditable, new Object[0]);
        }

        this.getViewTreeObserver().removeGlobalOnLayoutListener(this.onGlobalLayoutListener);
    }

    private void setRecycleListener(ListView listView) {
        listView.setRecyclerListener(new AbsListView.RecyclerListener() {
            public void onMovedToScrapHeap(View view) {
                ViewGroup viewGroup = (ViewGroup) view;
                MyHandWritingCoreView.callHandWritingRecycle(viewGroup);
            }
        });
    }

    public static void callHandWritingRecycle(ViewGroup viewGroup) {
        for (int i = 0; i < viewGroup.getChildCount(); ++i) {
            View child = viewGroup.getChildAt(i);
            if (child instanceof MyHandWritingCoreView) {
                MyHandWritingCoreView handWritingView = (MyHandWritingCoreView) child;
                handWritingView.cacheBitmap(handWritingView.getStrokes());
                if (handWritingView.mIsStrokesChanged && handWritingView.recycleListener != null) {
                    handWritingView.recycleListener.onRecycleListener();
                }
            } else if (child instanceof ViewGroup) {
                callHandWritingRecycle((ViewGroup) child);
            }
        }

    }

    public boolean pourIntoTouchEvent(MotionEvent event) {
        return this.handleTouchEvent(event);
    }

    public boolean isGeometryType() {
        return this.isGeometryType(this.mDrawType);
    }

    private boolean isGeometryType(DrawType drawType) {
        switch (drawType) {
            case CURVE:
            case DASH:
            case LINE:
            case DASHLINE:
            case ARROW:
            default:
                return false;
            //等腰
            case ISOSCELESTRIANGLE:
            case RHOMBUS://菱形
            case PARALLELOGRAM://平行四边形
            case TRIANGLE:
            case RECTANGLE:
            case TRAPEZIUM:
            case OVAL:
            case COORDINATE:
            case NUMBER_AXIS:
                return true;
        }
    }

    private boolean isDefDrawType(int drawTypeCode, DrawType defDrawType) {
        return defDrawType != null && defDrawType.getCode() == drawTypeCode;
    }

    public void setGeometryPaintColor(@ColorInt int color) {
        if (this.mGeometryListener != null) {
            this.mGeometryListener.handleEditableGeometry();
        }

        if (!this.mIsGeometryEditable && this.mGeometryPaint != null) {
            this.mGeometryPaint.setColor(color);
        }

    }

    public void setGeometryPaintStyle(@NonNull Paint.Style style) {
        if (this.mGeometryListener != null) {
            this.mGeometryListener.handleEditableGeometry();
        }

        if (!this.mIsGeometryEditable && this.mGeometryPaint != null) {
            this.mGeometryPaint.setStyle(style);
        }

    }

    public void setAxisUnit(int axisUnit) {
        if (axisUnit > 0) {
            this.mAxisUnit = axisUnit;
        }
    }

    public boolean isStrokeChange() {
        return this.mIsStrokesChanged;
    }

    public void resetStrokeChange() {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "resetStrokeChange()", new Object[0]);
        }

        this.mIsStrokesChanged = false;
    }

    public void setPenColor(@ColorInt int color) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "setPenColor >>> color = " + color, new Object[0]);
        }

        if (this.mGeometryListener != null) {
            this.mGeometryListener.handleEditableGeometry();
        }

        if (this.mPaint != null) {
            this.mPaint.setColor(color);
        }

        this.mSetPenColor = color;
    }

    public int getPenColor() {
        return this.mPaint != null ? this.mPaint.getColor() : 0;
    }

    public int getGeometryPenColor() {
        return this.mGeometryPaint != null ? this.mGeometryPaint.getColor() : 0;
    }

    public boolean setDrawType(DrawType type) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "setDrawType >>> type = " + type, new Object[0]);
        }

        if (this.mIsRubber) {
            if (HandWritingViewHelper.DEBUG) {
                XHLog.i(TAG, "rubber status not allow to set mDrawType!!!", new Object[0]);
            }

            return false;
        } else if (this.mPaint == null) {
            return false;
        } else {
            if (this.mGeometryListener != null) {
                this.mGeometryListener.handleEditableGeometry();
            }

            this.mDrawType = type;
            switch (this.mDrawType) {
                case CURVE:
                case LINE:
                    this.mPaint.setStyle(Paint.Style.STROKE);
                    if (this.mPaint.getPathEffect() != null) {
                        this.mPaint.setPathEffect((PathEffect) null);
                    }
                    break;
                case DASH:
                case DASHLINE:
                    this.mPaint.setStyle(Paint.Style.STROKE);
                    PathEffect effect = new DashPathEffect(new float[]{5.0F, 15.0F, 5.0F, 15.0F}, 1.0F);
                    this.mPaint.setPathEffect(effect);
                    break;
                case ARROW:
                    this.mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
                    if (this.mPaint.getPathEffect() != null) {
                        this.mPaint.setPathEffect((PathEffect) null);
                    }
                    break;
                case ISOSCELESTRIANGLE://等腰三角形
                case TRIANGLE:
                case RECTANGLE:
                case TRAPEZIUM:
                case OVAL:
                case RHOMBUS://菱形
                case PARALLELOGRAM://平行四边形
                    if (this.mGeometryPaint != null) {
                        this.mGeometryPaint.setStyle(Paint.Style.STROKE);
                    }
                    break;
                case COORDINATE:
                case NUMBER_AXIS:
                    if (this.mGeometryPaint != null) {
                        this.mGeometryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
                    }
            }

            return true;
        }
    }

    public DrawType getDrawType() {
        return this.mDrawType;
    }

    public boolean isRubber() {
        return this.mIsRubber;
    }

    public boolean getCanDraw() {
        return this.canDraw;
    }

    public void setCanDraw(boolean canDraw) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "canDraw = [" + canDraw + "]", new Object[0]);
        }

        this.canDraw = canDraw;
    }

    public Bitmap getBitmap() {
        if (this.writingViewBitmap == null) {
            if (this.getWidth() != 0 && this.getHeight() != 0) {
                this.writingViewBitmap = Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config.ARGB_4444);
            } else {
                this.writingViewBitmap = Bitmap.createBitmap(this.mWidth, this.mHeight, Bitmap.Config.ARGB_4444);
            }

            this.writingViewCanvas = new Canvas(this.writingViewBitmap);
        }

        this.writingViewBitmap.eraseColor(0);
        this.draw(this.writingViewCanvas);
        return this.writingViewBitmap;
    }

    public void setBitmap(Bitmap mBitmap) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "setBitmap", new Object[0]);
        }

        if (this.handWritingCanvas != null) {
            this.handWritingCanvas.drawBitmap(mBitmap, this.paintDither);
        }

    }

    public void setBitmap(Bitmap mBitmap, String stroke) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "setBitmap", new Object[0]);
        }

     /*   if (stroke != null) {
            int index = stroke.lastIndexOf("@");
            if (index > 0) {
                this.strokes = new StringBuilder(stroke.substring(index + 1));
            } else {
                this.strokes = new StringBuilder();
            }
        }*/

        if (this.handWritingCanvas != null) {
            this.handWritingCanvas.drawBitmap(mBitmap, this.paintDither);
        }

        this.invalidate();
    }

    public void setDebug(boolean isDebug) {
        HandWritingViewHelper.DEBUG = isDebug;
    }

    public void setMotionEventCallback(MotionEventCallback callback) {
        this.motionEventCallback = callback;
    }

    public IHandWritingViewCache getHandWritingViewCache() {
        return this.handWritingViewCache;
    }

    public View getActionDownView() {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "getActionDownView()", new Object[0]);
        }

        return this.actionDownView;
    }

    public void setActionDownView(View actionDownView) {
        if (HandWritingViewHelper.DEBUG) {
            XHLog.i(TAG, "setActionDownView()", new Object[0]);
        }

        this.actionDownView = actionDownView;
    }

    public int getmWidth() {
        return this.mWidth;
    }

    public int getmHeight() {
        return this.mHeight;
    }

    public void setHandWritingViewCache(IHandWritingViewCache handWritingViewCache) {
        this.handWritingViewCache = handWritingViewCache;
    }

    public void setRecycleListener(MyHandWritingView.RecycleListener recycleListener) {
        this.recycleListener = recycleListener;
    }

    public void setGeometryListener(IGeometryListener geometryListener) {
        this.mGeometryListener = geometryListener;
    }

    public boolean isGeometryEditable() {
        return this.mIsGeometryEditable;
    }

    public class CGPoint {
        double x;
        double y;

        CGPoint() {
        }

        public CGPoint(double x, double y) {
            this.x = x;
            this.y = y;
        }

        public String toString() {
            return "x=" + this.x + ", y=" + this.y;
        }
    }


    interface SplitCall {
        void splitCall(int var1, String var2);
    }
}
